package logic;
import java.util.ArrayList;
import java.util.HashMap;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;

import domain.Node;
import domain.Share;
import domain.StackHolder;


public class PreferenceHandler extends ItemHandler implements Observeable {
	
	// Counter for number of backupnodes
	private int m_BackupNodeId;
	
	private HashMap<String, Object> m_KeyValuePairs;
	private ArrayList<Observer> m_Observers;
	private PreferenceEnum m_PreferenceEnum;
	
	public PreferenceHandler() {
		m_KeyValuePairs = new HashMap<String, Object>();
		m_Observers = new ArrayList<Observer>();
	}
	
	@Override
	public void startDocument() throws SAXException {
		m_PreferenceEnum = PreferenceEnum.None;
		m_KeyValuePairs.clear();
		
		// Collection for backup nodes
		m_BackupNodeId = 0;
		m_KeyValuePairs.put(PreferenceEnum.BackUpNode.name(), new ArrayList<Node>());
		
	}
	
	@Override
	public void endDocument() throws SAXException {
		notifyObservers(logic.KeyAction.Preferences, m_KeyValuePairs);
	}
	
	private StackHolder createStackHolder(Attributes attributes) {
		
		StackHolder stackHolder;
		
		stackHolder = new StackHolder("",  // Name
				attributes.getValue("emailaddress"), 
				attributes.getValue("smtpserver"),
				attributes.getValue("emailusername"), 
				attributes.getValue("emailpassword"));
		
		return stackHolder;
		
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
		
		ArrayList<Node> backupNodes;
		Node host;
		Share share;
		StackHolder stackHolder;
		
		if (qName.equals("ip")) {
			m_PreferenceEnum = PreferenceEnum.IP;
		
		} else if (qName.equals("os")) {
			m_PreferenceEnum = PreferenceEnum.OS;
		
		} else if (qName.equals("clientsMountPoint")) {
			m_PreferenceEnum = PreferenceEnum.ClientsMountPoint;
		
		} else if (qName.equals("backupsMountPoint")) {
			m_PreferenceEnum = PreferenceEnum.BackupsMountPoint;
			
		} else if (qName.equals("sender")) {
			stackHolder = createStackHolder(attributes);
			m_KeyValuePairs.put(PreferenceEnum.Sender.name(), stackHolder);
			
		} else if (qName.equals("recipient")) {
			stackHolder = createStackHolder(attributes);
			m_KeyValuePairs.put(PreferenceEnum.Recipient.name(), stackHolder);
			
		} else if (qName.equals("backupnode")) {
			m_PreferenceEnum = PreferenceEnum.BackUpNode;
			
			// Fetch values from backupnode's attributes.
			backupNodes = (ArrayList<Node>) m_KeyValuePairs.get(PreferenceEnum.BackUpNode.name());
			
			// Initialize the host and add it to the backupNodes collection.
			host = new Node(m_BackupNodeId, attributes.getValue("name"), attributes.getValue("ipaddress"), null);
			backupNodes.add(m_BackupNodeId, host);
		
		} else if (qName.equals("share")) {
			backupNodes = (ArrayList<Node>) m_KeyValuePairs.get(PreferenceEnum.BackUpNode.name());
			host = backupNodes.get(m_BackupNodeId);
			share = new Share();
			share.setName((attributes.getValue("name")));
			share.setUsername((attributes.getValue("username")));
			share.setPassword((attributes.getValue("password")));
			host.addShare(share);
		}
	}
	
	@Override
	public void endElement(String uri, String localName, String qName) throws SAXException {
		if (qName.equals("backupnode")) {
			m_BackupNodeId++;
		}
	}
	
	@Override
	public void characters(char[] ch, int start, int length) throws SAXException {
		
		switch (m_PreferenceEnum) {
		
			case IP:
			case OS:
			case BackupsMountPoint:
			case ClientsMountPoint:
				m_KeyValuePairs.put(m_PreferenceEnum.toString(), new String(ch, start, length));
				m_PreferenceEnum = PreferenceEnum.None;
				break;
				
			case BackUpNode:
			case StorageNode:
			case None:
				break;
		
			default:
				break;
		}
	}

	public synchronized void notifyObservers() {
		
		for (Observer o : m_Observers) {
			o.update();
		}
	}

	public void addObserver(Observer observer) {
		m_Observers.add(observer);
		
	}

	public void removeObserver(Observer observer) {
		m_Observers.remove(observer);
	}

	public void notifyObservers(logic.KeyAction keyAction, HashMap<String, Object> keyValuePairs) {
		
		for (Observer o : m_Observers) {
			o.update(keyAction, keyValuePairs);
		}
	}
}
